/* 场景构建工具数据结构定义 */
import * as THREE from "three";
import type { Dictionary } from "./utils/types";

/** PocketBase File Single 类型：提交时是 File 或空 返回时是 string 或 空 */
type PbFileSingle = File | string | null | undefined;

// MARK: 全局设置 ---------------------------------------------------------------------------------

/** 全局设置文件(config.json)数据结构 */
export type GlobalConfig = {
  currentProjectName: string;
  launchTimes: number;
  saveTimes: number;
};

/** 项目设置文件(project.json)数据结构 */
export type ProjectConfig = {
  categoryGroups: CategoryGroup[];
  generate: {
    cabinet: GenerateCabinetConfig;
    station: GenerateStationConfig;
  };
};

/** 设备室生成设置 */
export type GenerateCabinetConfig = {
  boardTypes: BoardTypeConfig[];
  boardNamePrefix: string;
  cabinetStep: { x: number; z: number };
  firstCabinetPos: { x: number; y: number; z: number };
  cabinetCapacityPerRow: number;
  boardWidth: number;
};
export type BoardTypeConfig = {
  typeName: string;
  modelId: string;
};

/** 车站场景生成设置 */
export type GenerateStationConfig = {
  segmentedLoftModels: LoftSegmented[];
  stretchableLoftModels: LoftStretchable[];
  independentModels: IndependentModel[];
};
export type LoftSegmented = {
  name: string;
  modelId5M: string;
  modelId20M: string;
};
export type LoftStretchable = {
  name: string;
  modelId: string;
  originalLength: number;
};
export type IndependentModel = {
  name: string;
  modelId: string;
};

// MARK: 模型库 ====== ----------------------------------------------------------------------------

/** 模型列表数据 */
export type ModelListItem = {
  id: string;
  name: string; // 模型名称
  categoryName?: string; // 模型分类
  categories: Dictionary<string>; // 模型分类
  model: string; // 模型文件路径
  cover: string; // 没有封面时，返回空字符串("")
  description: string;
  boundingBox: ModelBoundingBox; // 包围盒
  stateAspects: StateAspect[]; // 状态设置
};

/** 上传模型数据 */
export type ModelUploadBody = {
  tempFileName: string; // 模型临时文件名
  modelName: string; // 模型名称
  categoryName?: string; // 分类名称（旧）
  categories: Dictionary<string>; // 模型分类（新）
  coverDataUrl: string; // 封面的 DataURL
  boundingBox: ModelBoundingBox; // 包围盒
  description: string; // 备注
};

/** 编辑模型数据 */
export type ModelEditBody = {
  id: string; // 模型ID
  tempFileName: string; // 模型临时文件名
  modelName: string; // 新模型名称
  categoryName?: string; // 分类名称（旧）
  categories: Dictionary<string>; // 模型分类（新）
  coverDataUrl: string; // 封面的 DataURL
  boundingBox: ModelBoundingBox; // 包围盒
  description: string; // 备注
  stateAspects: StateAspect[]; // 状态设置
};

// MARK: 模型分类 ---------------------------------------------------------------------------------

/** 模型分类标签分组 */
export type CategoryGroup = {
  name: string;
  categoryItems: CategoryItem[];
  unCategoryModelCount?: number; // 只是为了让前端显示“未分类”的模型数量使用
};

/** 模型分类标签条目 */
export type CategoryItem = {
  categoryName: string;
  categoryIcon: string;
  modelCount?: number; // 只是为了让前端显示此分类下模型数量使用
};

/** 编辑模型分类标签时提供的分组信息 */
// 改动: 类型组和标签的名称拆分为了 old 和 new 两个，用于让后端判断是增删改中的哪一个
// 增: '' -> "新标签", 删: '废标签' -> '', 改: '旧标签' -> '改标签'
export type EditingCategoryGroup = {
  oldName: string;
  newName: string;
  categoryItems: EditingCategoryItem[];
};
/** 编辑模型分类标签时提供的条目信息 */
export type EditingCategoryItem = {
  oldName: string;
  newName: string;
  categoryIcon: string;
};

// MARK: 模型配置 ---------------------------------------------------------------------------------

/** 模型信息 */
export type ModelJson = {
  id: string; // ID
  name: string; // 模型名称
  categoryName?: string; // 模型分类名称（旧）
  categories: Dictionary<string>; // 模型分类（新）
  boundingBox: ModelBoundingBox; // 模型包围盒
  description: string; // 备注
  stateAspects: StateAspect[]; // 状态设置
};

/** 模型包围盒 */
// TODO 2.0: position 改为 center，ModelBoundingBox与 SceneBoundingBox 合并为 BoundingBox
export type ModelBoundingBox = {
  position: [number, number, number]; // 中心位置
  size: [number, number, number]; // 大小
};

// MARK: 模型状态设置 -----------------------------------------------------------------------------

export type AffectingProperty =
  | "COLOR"
  | "POSITION"
  | "ROTATION"
  | "VISIBLE"
  | "TEXT";
export type StateAspect = {
  aspectName: string;
  dataPropName: string;
  affectingProperties: AffectingProperty[];
  stateValues: StateValue[];
  textStateSetting?: TextStateSetting;
};
export type StateValue = {
  name: string;
  dataPropValue: string;
  partSettings: PartSetting[];
};
export type TextStateSetting = {
  pivotPosition: [number, number, number]; // 轴心位置
  fontSize: number; // 字号
  fontColor: [number, number, number]; // 字色
  fontWeight: FontWeight; // 字重
  defaultContent?: string; // 默认文字内容
  textAlign?: "left" | "center" | "right"; // 水平对齐
  verticalAlign?: "top" | "center" | "bottom"; // 垂直对齐
  areaSize?: [number, number]; // 区域大小
  padding?: [number, number]; // 内边距设置
  backgroundUrl: string; // 背景图片URL
};
export type FontWeight = "REGULAR" | "BOLD";
export type PartSetting = {
  targetPartName: string;
  color: [number, number, number];
  position: [number, number, number];
  rotation: [number, number, number];
  visible: boolean;
};

// MARK: 场景库 ====== ----------------------------------------------------------------------------

/** 场景列表 */
export type SceneListItem = {
  name: string; // 场景名称（也就是不带后缀的文件名）
  path: string; // 场景所在路径，默认为斜杠("/")，代表在根目录中
  projectName: string; // 所在项目名称
  cover: string; // 封面文件路径，没有封面时，返回空字符串("")
  url: string; // 场景 JSON 文件的路径
  tags: string[]; // 标签
  description: string; // 备注
};

/** 场景元信息 */
export type SceneMeta = {
  // name: string // 场景名称（不要了，改为用文件名存储）
  tags: string[]; // 标签
  description: string; // 备注
};

/** 场景编辑请求数据 */
export type SceneEditBody = {
  path: string; // 场景所在路径
  oldSceneName: string; // 原场景名称
  newSceneName: string; // 新场景名称
  tags: string[]; // 标签
  description: string; // 备注
};

// MARK: 场景配置 ---------------------------------------------------------------------------------

/** 场景配置信息 */
export type SceneJson = {
  version: number;
  boundingBox: SceneBoundingBox;
  environment: SceneEnvConfig;
  models: ModelConfig[];
  cameras?: CameraSpot[];
  cameraInEditor: CameraSpot;
  pointMarker: {
    groups: PointMarkerGroupData[];
  };
};

/** 场景包围盒 */
export type SceneBoundingBox = {
  center: [number, number, number];
  size: [number, number, number];
};

/** 场景环境设置 */
export type SceneEnvConfig = {
  sky: SceneSkyConfig; // 天空设置
  ground: SceneGroundConfig; // 地面设置
  fog: SceneFogConfig; // 雾气设置
  objectStyle: SceneObjectStyleConfig; // 物体风格设置
};

/** 场景天空设置 */
export type SceneSkyConfig = {
  type: SceneSkyType; // 天空类型，“环境贴图”和“纯色”
  envMap: string; // 天空设置：最简单，只有一个环境贴图URL
  color: [number, number, number]; // 天空颜色，默认白色 [1.0, 1.0, 1.0]
};

/** 天空类型，“环境贴图”和“纯色” */
export type SceneSkyType = "ENVMAP" | "COLOR";

/** 场景地面设置 */
export type SceneGroundConfig = {
  materialId: string; // 材质ID
  materialPreviewUrl: string; // 材质预览图
  groundSize: number; // 地面大小，取值范围：128, 256, 512, 1024, 2048
  textureScale: number; // 纹理缩放，取值范围：0.25, 0.5, 1, 2, 4
};

/** 场景雾效设置 */
export type SceneFogConfig = {
  type: SceneFogType; // 雾气类型，“线性雾” 或 “指数雾”
  color: [number, number, number]; // 雾气颜色，默认白色 [1.0, 1.0, 1.0]
  // 仅在“线性雾”类型有效
  near: number; // 距离范围-最近距离
  far: number; // 距离范围-最远距离
  // 仅在“指数雾”类型有效
  density: number; // 雾气浓度
};

/** 雾气类型，对应 null, THREE.Fog 和 THREE.FogExp2 */
export type SceneFogType = "NONE" | "LINEAR" | "EXP";

/** 场景物体风格设置 */
export type SceneObjectStyleConfig = {
  type: SceneObjectStyleType; // 物体风格类型，“写实” 或 “科幻”
  // 仅在“科幻”类型有效
  frameColor: [number, number, number]; // 线框颜色，默认白色 [1.0, 1.0, 1.0]
  surfaceColor: [number, number, number]; // 表面颜色，默认白色 [1.0, 1.0, 1.0]
  surfaceOpacity: number; // 表面不透明度，范围 0-1
};

/** 物体风格类型，“写实 REALISTIC” 或 “科幻 SCI_FI” */
export type SceneObjectStyleType = "REALISTIC" | "SCI_FI";

/** 物体风格材质 */
export type SceneObjectStyleMaterials = {
  frameMaterial: THREE.MeshBasicMaterial;
  surfaceMaterial: THREE.MeshBasicMaterial;
};

// MARK: 场景节点配置 -----------------------------------------------------------------------------

/** 场景节点设置 */
export type ModelConfig = {
  modelId: string; // 模型文件ID
  name: string; // 物体名称，默认是模型名称
  code: string; // 模型的编号
  position: [number, number, number]; // 位置
  rotation: [number, number, number, THREE.EulerOrder]; // 旋转，格式为欧拉角 x,y,z,order
  scale: [number, number, number]; // 缩放
  defaultStateSettings?: StateAspectSetting[]; // 默认状态设置
  specialAttribute: object; // 模型的特有属性
  visible?: boolean; // 默认是否显示
  children: ModelConfig[]; // 支持层级嵌套
  materialReplacements: ModelMaterialReplaceConfig[]; // 模型材质替换设置
  renderMode: ModelRenderMode; // 渲染模式
};

/** 场景节点用户数据，即 Object3D.userData */
export type SceneNodeData = {
  // 【模型物体】
  // 持久化数据（ModelConfig 内）
  modelId: string; // 模型ID
  modelName: string; // 模型名称
  // name: string // 物体名称。不用 userData 保存，用 Object3D:name
  code: string; // 物体编号
  renderMode: ModelRenderMode; // 渲染模式
  specialAttribute: object; // 特有属性
  defaultStateSettings?: StateAspectSetting[]; // 默认状态设置
  materialReplacements?: ModelMaterialReplaceConfig[]; // 模型材质替换设置
  // 临时数据
  isModel?: boolean; // 是否为模型
  isGroup?: boolean; // 是否为组
  expanded?: boolean; // 是否已展开（仅用于世界大纲里）
  locked?: boolean; // 是否已锁定（仅用于世界大纲里）
  searchMatched?: boolean; // 关键字搜索匹配成功（仅用于世界大纲里）

  // 【非模型物体】
  // 场景根容器
  isModelGroup?: boolean; // 是否为 ModelGroup（场景内所有模型的根容器）findModelByUuid 和 findModelByCode 会用到
  // 辅助器根容器
  isHelperGroup?: boolean; // 是否为 HelperGroup（场景内所有辅助器（非模型）的根容器）
  // 文字状态容器
  isTextGroup?: boolean; // 是否为 TextGroup（物体内多个文字状态的容器）
  // 文字对象
  isTextObject?: boolean; // 是否为 TextObject（文字对象）
  textObjectStateAspectName?: string; // 此 TextObject 对应的状态方面
  // 物体风格线框
  isFrameGenerated?: boolean; // （仅模型物体上会有）是否已经为模型物体生成了线框物体
};

/** 模型状态设置（目前只有初始状态会用到） */
export type StateAspectSetting = {
  // 状态方面名称
  aspectName: string;
  // 状态值，对于“颜色、位置、旋转”状态方面类型，它是状态值的名称（StateValue.name）
  // 而对于“文字”状态方面类型，它是要显示的文字
  stateValue: string;
};

/** 模型材质替换设置 */
export type ModelMaterialReplaceConfig = {
  meshIndex: number;
  materialId: string;
};

/** 模型渲染模式，“场景物体风格”或“写实” */
export type ModelRenderMode = "SCENE_OBJECT_STYLE" | "REALISTIC";

// MARK: 材质库 ====== ----------------------------------------------------------------------------

/** 材质列表 */
export type MaterialConfig = {
  // 基础信息
  id: string | null; // 材质ID
  name: string; // 材质名称，如“墙纸-拼花-黄色-01”，不能重复
  previewImage: PbFileSingle; // 预览图片，由 Three.js 预览组件从 Canvas 生成
  // 材质分类
  substanceType: string; // 实物分类，如“织物”，单选
  positionType: string[]; // 位置分类，如“墙”，多选
  sourceType: string; // 来源分类，“自然”和“人造”二选一
  statusType: string; // 状态分类，“崭新”和“破旧”二选一
  // 材质设置
  tintColor: [number, number, number]; // 染色(基础色)，RGB 格式，默认为白色 [1.0, 1.0, 1.0]
  isTransparent: boolean; // 是否为半透明材质，默认为“否”
  isDoubleSide: boolean; // 是否为双面材质，默认为“否”
  // 贴图
  diffuseMapUrl: string; // 漫反射贴图
  normalMapUrl?: string; // 法线贴图
  emissiveMapUrl?: string; // 自发光贴图
  aoMapUrl: string; // AO贴图
  roughnessMapUrl: string; // 粗糙度贴图
  metalnessMapUrl: string; // 金属度贴图
  // 强度值
  emissiveIntensity: number; // 自发光强度，默认为 1，范围 0-2
  aoMapIntensity: number; // AO贴图强度，默认为 1，范围 0-1
  roughnessValue: number; // 粗糙度，默认为 1，范围 0-1
  metalnessValue: number; // 金属度，默认为 0，范围 0-1
};

// MARK: 大纲视图 ===== ---------------------------------------------------------------------------

/** 相机视角 */
export type CameraSpot = {
  name: string;
  position: [number, number, number];
  targetPosition: [number, number, number];
};

/** 点位标签组设置 */
export type PointMarkerGroupData = {
  id: number;
  name: string;
  iconUrlNormal: string;
  iconUrlSelected?: string;
  iconWidth?: number;
  iconHeight?: number;
  anchorPoint: [number, number];
  points: PointMarkerItemData[];
};
/** 点位标签项设置 */
export type PointMarkerItemData = {
  id: number;
  name: string;
  iconUrlNormal?: string;
  iconUrlSelected?: string;
  position: [number, number, number];
};
